package org.wgc.study.utils.fluentassembler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/***
 *@title AsyncDataFetcher
 *@description
 *@author wgc_j
 *@version 1.0.0
 *@create 2025-08-01 9:21
 **/
public class AsyncDataFetcher {
/*    工作原理
    注册异步任务：通过 register 方法注册多个异步数据提供者（Supplier），每个提供者对应一个 DataKey，作为后续获取数据的标识。
    并行执行任务：调用 executeAndAssemble 方法时，会并行触发所有已注册的异步任务，使用 CompletableFuture 和线程池来实现异步执行。
    等待任务完成：使用 CompletableFuture.allOf(...).join() 等待所有异步任务完成，将获取到的数据存储在 PreparedData 对象中。
    数据组装：遍历源数据列表，调用用户提供的组装函数 assemblerFunc，将 PreparedData 中的异步数据与源数据进行组装，最终返回组装好的结果列表。*/
   /* register(name, supplier)：注册一个数据准备任务。它返回一个 DataKey<T>，作为未来获取该数据的“凭证”。
    executeAndAssemble(sourceList, assemblerFunc)：这是核心调度方法。它首先并行触发所有已注册的 supplier，然后使用 CompletableFuture.allOf(...).join() 等待所有任务完成。最后，它遍历源数据列表，调用用户提供的组装函数 assemblerFunc，并将准备好的数据容器 preparedData 传给它。
    addFutureTask：一个私有的泛型辅助方法，用于解决Java泛型擦除导致在 forEach 中类型不匹配的问题，确保类型安全。*/
    private final Map<DataKey<?>, Supplier<?>> suppliers = new HashMap<>();
    private final Executor executor;

    /**
     * 使用默认的 ForkJoinPool.commonPool() 作为线程池。
     */
    public AsyncDataFetcher() {
        this(null);
    }

    /**
     * 使用指定的线程池。
     * @param executor 用于执行异步任务的线程池
     */
    public AsyncDataFetcher(Executor executor) {
        this.executor = executor;
    }

    /**
     * 注册一个异步数据提供者。
     *
     * @param name      一个描述性名称，用于创建DataKey
     * @param supplier  提供数据的Supplier，它将被异步执行
     * @return 一个类型安全的DataKey，用于后续获取数据
     */
    public <T> DataKey<T> register(String name, Supplier<T> supplier) {
        DataKey<T> key = DataKey.of(name);
        suppliers.put(key, supplier);
        return key;
    }

    /**
     * 执行所有已注册的异步查询，等待它们完成后，使用结果来组装对象列表。
     *
     * @param sourceList    源对象列表
     * @param assemblerFunc 组装函数，接收单个源对象和准备好的数据容器，返回组装好的目标对象
     * @param <S>           源类型
     * @param <T>           目标类型
     * @return 组装好的目标对象列表
     */
    public <S, T> List<T> executeAndAssemble(List<S> sourceList, BiFunction<S, PreparedData, T> assemblerFunc) {
        if (sourceList == null || sourceList.isEmpty()) {
            return new ArrayList<>();
        }

        List<CompletableFuture<Void>> futures = new ArrayList<>();
        PreparedData preparedData = new PreparedData();

        // **修改点：用 for-each 循环替代 forEach lambda，并调用泛型辅助方法**
        for (Map.Entry<DataKey<?>, Supplier<?>> entry : suppliers.entrySet()) {
            CompletableFuture<Void> future = addFutureTask(entry.getKey(), entry.getValue(), preparedData);
            futures.add(future);
        }

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        return sourceList.stream()
                .map(source -> assemblerFunc.apply(source, preparedData))
                .collect(Collectors.toList());
    }

    /**
     * **新增的私有泛型辅助方法**
     * 这个方法捕获了通配符 '?' 对应的具体类型 V。
     *
     * @param key          数据键
     * @param supplier     数据提供者
     * @param preparedData 数据容器
     * @param <V>          被捕获的具体类型
     * @return 一个 CompletableFuture<Void>，代表了异步任务的完成状态
     */
    @SuppressWarnings("unchecked")
    private <V> CompletableFuture<Void> addFutureTask(DataKey<?> key, Supplier<?> supplier, PreparedData preparedData) {
        // 在这里，我们将 Supplier<?> 安全地转换为 Supplier<V>
        Supplier<V> typedSupplier = (Supplier<V>) supplier;

        // 我们将 DataKey<?> 安全地转换为 DataKey<V>
        DataKey<V> typedKey = (DataKey<V>) key;

        return runAsync(typedSupplier, executor)
                .thenAccept(result -> preparedData.put(typedKey, result));
    }

    // 辅助方法，处理 Executor 为 null 的情况
    private <U> CompletableFuture<U> runAsync(Supplier<U> supplier, Executor executor) {
        if (executor != null) {
            return CompletableFuture.supplyAsync(supplier, executor);
        } else {
            return CompletableFuture.supplyAsync(supplier);
        }
    }

    public static void main(String[] args) {
        // 创建一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);
        // 创建 AsyncDataFetcher 实例
        AsyncDataFetcher fetcher = new AsyncDataFetcher(executor);

        // 注册异步数据提供者1
        DataKey<String> dataKey1 = fetcher.register("data1", () -> {
            // 模拟耗时操作
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "Async Data 1";
        });

        // 注册异步数据提供者2
        DataKey<Integer> dataKey2 = fetcher.register("data2", () -> {
            // 模拟耗时操作
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return 123;
        });

        // 准备源数据列表
        List<String> sourceList = new ArrayList<>();
        sourceList.add("Source Item 1");
        sourceList.add("Source Item 2");

        // 定义组装函数
        BiFunction<String, PreparedData, String> assemblerFunc = (source, preparedData) -> {
            String data1 = preparedData.get(dataKey1);
            Integer data2 = preparedData.get(dataKey2);
            return source + " - " + data1 + " - " + data2;
        };

        // 执行并组装数据
        List<String> resultList = fetcher.executeAndAssemble(sourceList, assemblerFunc);

        // 输出结果
        for (String result : resultList) {
            System.out.println(result);
        }

        // 关闭线程池
        executor.shutdown();
    }
}
